using System;
using System.Collections;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI;
using System.Drawing;
using Microsoft.SharePoint;
using net.windward.api.csharp;
using net.windward.utils.ado;
using System.IO;
using System.Net;
using System.Xml;
using System.Data.Common;
using System.Web.Caching;
using System.Web;
using net.windward.util;
using log4net;

namespace ArrowWebParts
{
    /// <summary>
    /// A wizard web part that walks the user through creating a windward report data source file (*.datadef) in SharePoint.
    /// </summary>
    public class DataDefinitionWebPart : WebPart
    {
        #region fields

        /// <summary>
        /// The ASP.NET Control Wizard object
        /// </summary>
        private Wizard wizzy;
        /// <summary>
        /// Textbox containing the name of the *.datadef file
        /// </summary>
        private TextBox title;
        /// <summary>
        /// A validator to ensure a non-empty title
        /// </summary>
        private RequiredFieldValidator titleTextBoxValidator;
        /// <summary>
        /// Textbox for the user to input a description of the data source
        /// </summary>
        private TextBox description;
        /// <summary>
        /// A DropDownList containing all the sites of the current user; used to select the site in which to save the *.datadef
        /// </summary>
        private DropDownList saveLocationSiteDropDownList;
        /// <summary>
        /// A DropDownList containing all the document libraries of the current site; used to select the document library in which to save the *.datadef
        /// </summary>
        private DropDownList saveLocationLibraryDropDownList;
        /// <summary>
        /// A DropDownList containing all the folders of the current doc lib; used to select the folder in which to save the *.datadef
        /// </summary>
        private DropDownList saveLocationFolderDropDownList;
        /// <summary>
        /// A validator to ensure a valid document library
        /// </summary>
        private RequiredFieldValidator saveLocationLibraryDropDownListValidator;
        /// <summary>
        /// Used to choose the type of data source, either XML or SQL
        /// </summary>
        private RadioButtonList dataType;
        /// <summary>
        /// Used to select the vendor among all available vendors found on the server
        /// </summary>
        private DropDownList vendor;
        /// <summary>
        /// A validator to ensure a valid vendor
        /// </summary>
        private RequiredFieldValidator vendorDropDownListValidator;
        /// <summary>
        /// Chooses the style of the remaining steps in the wizard for an SQL data source; either Step by Step mode or Connection String mode
        /// </summary>
        private RadioButtonList inputType;
        /// <summary>
        /// Used to allow the user to select a provider for a vendor, if applicable
        /// </summary>
        private DropDownList provider;
        /// <summary>
        /// A validator to ensure a valid provider
        /// </summary>
        private RequiredFieldValidator providerDropDownListValidator;
        /// <summary>
        /// Used to determine which control is used for selecting the server name; either dropDownServer or textBoxServer
        /// </summary>
        private RadioButtonList serverSelectionType;
        /// <summary>
        /// User may choose any servers Windward Reports can automatically find
        /// </summary>
        private DropDownList dropDownServer;
        /// <summary>
        /// User may manually input the server name here
        /// </summary>
        private TextBox textBoxServer;
        /// <summary>
        /// User chooses whether of not he/she needs to enter a username/password to access the server
        /// </summary>
        private RadioButtonList loginType;
        /// <summary>
        /// Server access username
        /// </summary>
        private TextBox username;
        /// <summary>
        /// Server access password
        /// </summary>
        private TextBox password;
        /// <summary>
        /// Allows user to select a database using previously given server information, if applicable
        /// </summary>
        private DropDownList database;
        /// <summary>
        /// A validator to ensure a valid database
        /// </summary>
        private RequiredFieldValidator databaseDropDownListValidator;
        /// <summary>
        /// TextBox to allow the user to directly input the connection string as text
        /// </summary>
        private TextBox connStr;
        /// <summary>
        /// A validator to ensure a present connection string
        /// </summary>
        private RequiredFieldValidator connStrTextBoxValidator;
        /// <summary>
        /// A list containing all sites accessible for the current user; used to find an XML document
        /// </summary>
        private DropDownList xmlSitesDropDownList;
        /// <summary>
        /// A list containing all document libraries accessible from the current site; used to find an XML document
        /// </summary>
        private DropDownList xmlLibs;
        /// <summary>
        /// Used to select an XML file to use as a data source
        /// </summary>
        private DropDownList xmlFiles;
        /// <summary>
        /// A validator to ensure a valid xml file
        /// </summary>
        private RequiredFieldValidator xmlFilesDropDownListValidator;
        /// <summary>
        /// Used to input the username needed to access the XML file to be used as a data source
        /// </summary>
        private TextBox xmlUsernameTextBox;
        /// <summary>
        /// Used to input the password needed to access the XML file to be used as a data source
        /// </summary>
        private TextBox xmlPasswordTextBox;
        /// <summary>
        /// A status message containing the title chosen by the user
        /// </summary>
        private Label labelTitle;
        /// <summary>
        /// A status message containing the description chosen by the user
        /// </summary>
        private Label labelDescription;
        /// <summary>
        /// A status message containing the name of the document library to use as the save location chosen by the user
        /// </summary>
        private Label labelLocation;
        /// <summary>
        /// A status message containing the connection string for the data source chosen by the user
        /// </summary>
        private Label labelConnStr;
        /// <summary>
        /// A button used to test the connection string by attempting to access the data source
        /// </summary>
        private Button testBtn;
        /// <summary>
        /// A status message on whether the test passes or fails
        /// </summary>
        private Label testLabel;
        /// <summary>
        /// A status message on whether the *.datadef file is successfully created
        /// </summary>
        private Label resultLabel;
        /// <summary>
        /// The logger.
        /// </summary>
        private static ILog log = LogManager.GetLogger(typeof(DataDefinitionWebPart));
        /// <summary>
        /// overview step 0
        /// </summary>
        private const int STEP_OVERVIEW = 0;
        /// <summary>
        /// vendor step 1
        /// </summary>
        private const int STEP_VENDOR = 1;
        /// <summary>
        /// provider step 2
        /// </summary>
        private const int STEP_PROVIDER = 2;
        /// <summary>
        /// server and creds step 3
        /// </summary>
        private const int STEP_SERVER_CREDS = 3;
        /// <summary>
        /// db step 4
        /// </summary>
        private const int STEP_DB = 4;
        /// <summary>
        /// conn str step 5
        /// </summary>
        private const int STEP_CONN_STR = 5;
        /// <summary>
        /// xml file step 6
        /// </summary>
        private const int STEP_XML_FILE = 6;
        /// <summary>
        /// review step 7
        /// </summary>
        private const int STEP_REVIEW = 7;
        /// <summary>
        /// Contains any error messages to be displayed for the user at STEP_XML_FILE.
        /// </summary>
        private Label lblXmlFileStepErrorMessage;

        #endregion

        /// <summary>
        /// Creates the controls of the web part; called everytime the page does a postback
        /// </summary>
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            // create the controls
            try
            {
                // trace log
                if (log.IsDebugEnabled)
                    log.Debug("Creating data def child controls.");

                try
                {
                    // read in license from web.config
                    ArrowUtils.InitializeArrow(string.Concat(Page.Request.PhysicalApplicationPath, "\\web.config"));
                }
                catch (LicenseException lex)
                {
                    ArrowUtils.LogFatalException(log, lex);
                    Controls.Add(new LiteralControl(string.Format("License Error: {0}", lex.Message)));
                    return;
                }

                // Initialize and set up wizard
                wizzy = new Wizard();
                wizzy.ID = "DataSourceWizzy";
                wizzy.Width = 550;//725;
                wizzy.Height = 400;// 362;
                wizzy.StepStyle.VerticalAlign = VerticalAlign.Top;
                wizzy.BorderStyle = BorderStyle.Solid;
                wizzy.BorderColor = Color.FromName("Black");
                wizzy.BorderWidth = 1;
                wizzy.SideBarStyle.Width = 150;
                wizzy.SideBarStyle.VerticalAlign = VerticalAlign.Top; ;
                wizzy.NextButtonClick += new WizardNavigationEventHandler(wizzy_NextButtonClick);
                wizzy.FinishButtonClick += new WizardNavigationEventHandler(wizzy_FinishButtonClick);
                wizzy.DisplaySideBar = false;

                Button tempButton = (Button)wizzy.FindControl("StepNavigationTemplateContainerID$StepNextButton");
                tempButton.ValidationGroup = "validationGroup" + this.UniqueID;
                tempButton.CausesValidation = true;
                Button tempButton2 = (Button)wizzy.FindControl("StartNavigationTemplateContainerID$StartNextButton");
                tempButton2.ValidationGroup = "validationGroup" + this.UniqueID;
                tempButton2.CausesValidation = true;

                // Create and add each table to the wizard
                for (int i = 0; i < 8; i++)
                {
                    WizardStepBase newStep = new WizardStep();
                    newStep.ID = "Step" + (i).ToString();
                    newStep.Title = "Step" + (i).ToString();

                    newStep.Controls.Add(createTable(i));

                    wizzy.WizardSteps.Add(newStep);
                }
                Controls.Add(wizzy);

                if (log.IsDebugEnabled)
                    log.Debug("Finished creating child controls.");
            }
            catch (Exception ex)
            {
                // log the exception info
                ArrowUtils.LogFatalException(log, ex);

                // give the user an easy message
                Controls.Clear();
                Controls.Add(new LiteralControl("There was an error creating the web part controls."));
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (lblXmlFileStepErrorMessage != null)
                lblXmlFileStepErrorMessage.Text = string.Empty;
        }

        #region delegate functions

        /// <summary>
        /// This function is called when ever the next button is pressed in the wizard.
        /// Manages the forward transitions between wizard steps.
        /// The function uses the step it is moving from and information from the user input to determine the next step
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void wizzy_NextButtonClick(object sender, WizardNavigationEventArgs e)
        {
            //SPWeb site = SPContext.Current.Web;
            WrVendor selectedVendor;

            switch (e.CurrentStepIndex)
            {
                case STEP_OVERVIEW: // intro screen
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from overview step");
                    /*if (title.Text == "")
                    {
                        titleStatusLabel.Text = "* You must enter a title";
                        wizzy.ActiveStepIndex = STEP_OVERVIEW;
                    }
                    else
                        titleStatusLabel.Text = "";*/
                    if (dataType.SelectedValue == "XML")
                    {
                        wizzy.ActiveStepIndex = STEP_XML_FILE;
                    }
                    else
                    {
                        populateVendors();
                    }
                    break;
                case STEP_VENDOR: // vendor and wiz type
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from vendor step");
                    selectedVendor = createVendor();

                    if (inputType.SelectedValue == "ConnStr")
                    {
                        wizzy.ActiveStepIndex = STEP_CONN_STR;
                    }
                    else if (selectedVendor.HasProviders)
                    {
                        populateProviders();
                    }
                    else if (!selectedVendor.HasProviders)
                    {
                        // determine whether to enable/disable server drop-down list
                        if (selectedVendor.DatabaseMode == WrVendor.DATABASE_MODE.NEVER)
                        {
                            // disable server drop-down list
                            serverSelectionType.Items[0].Enabled = false;
                            dropDownServer.Enabled = false;

                            // select server manual entry
                            serverSelectionType.Items[0].Selected = false;
                            serverSelectionType.Items[1].Selected = true;
                        }
                        else
                        {
                            // enable server drop-down list
                            serverSelectionType.Items[0].Enabled = true;
                            dropDownServer.Enabled = true;

                            // select server drop-down list mode
                            serverSelectionType.Items[0].Selected = true;
                            serverSelectionType.Items[1].Selected = false;
                        }

                        // setup server drop-down list
                        dropDownServer.Items.Clear();
                        if(selectedVendor.CanEnumerateServers)
                            populateServers();
                        wizzy.ActiveStepIndex = STEP_SERVER_CREDS;
                    }
                    break;
                case STEP_PROVIDER: // provider
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from provider step");
                    // ADD: check login settings
                    selectedVendor = createVendor();
                    if (selectedVendor.CanEnumerateServers)
                        populateServers();
                    break;
                case STEP_SERVER_CREDS: // server and login
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from server step");
                    ViewState["pass"] = password.Text.Trim();
                    selectedVendor = createVendor();
                    
                    // skip db step for DATABASE_MODE.NEVER
                    if (selectedVendor.DatabaseMode == WrVendor.DATABASE_MODE.NEVER)
                        advanceToSummary();
                    else if (selectedVendor.CanEnumerateDatabases)
                    {
                        try
                        {
                            populateDatabases();
                        }
                        catch (Exception ex)
                        {
                            //ex.Message;
                            //ex.StackTrace;
                        }
                    }
                    else
                        advanceToSummary();
                    break;
                case STEP_DB: // db
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from db step");
                    populateSummary(generateSqlConnStr(false));
                    wizzy.ActiveStepIndex = STEP_REVIEW;
                    break;
                case STEP_CONN_STR: // conn string
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from conn str step");
                    populateSummary(connStr.Text.Trim());
                    wizzy.ActiveStepIndex = STEP_REVIEW;
                    break;
                case STEP_XML_FILE: // xml file
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from xml file step");
                    // bugbug -> need to hit target site, not current site
                    ViewState["xmlPass"] = xmlPasswordTextBox.Text.Trim();
                    Guid fileLibID = new Guid(xmlLibs.SelectedValue);
                    Guid fileID = new Guid(xmlFiles.SelectedValue);
                    try
                    {
                        string absolutePath = getAbsolutePath(new Guid(xmlSitesDropDownList.SelectedValue), new Guid(xmlLibs.SelectedValue), new Guid(xmlFiles.SelectedValue));
                        populateSummary(absolutePath);
                    }
                    catch (ArgumentException ex)
                    {
                        lblXmlFileStepErrorMessage.Text = "The selected file no longer exists, or you do not have permission to access the file.";
                        e.Cancel = true;

                    }
                    break;
                case STEP_REVIEW: // summary
                    if (log.IsDebugEnabled)
                        log.Debug("Moving from review step");
                    //Nothing
                    break;
            }
        }
        /// <summary>
        /// Populates the summary and advances the wizard to <see cref="STEP_REVIEW"/>.
        /// </summary>
        private void advanceToSummary()
        {
            populateSummary(generateSqlConnStr(false));
            wizzy.ActiveStepIndex = STEP_REVIEW;
        }
        /// <summary>
        /// This function is called when ever the finish button is pressed in the wizard.
        /// Generates the *.datadef file from all of the user information
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void wizzy_FinishButtonClick(object sender, WizardNavigationEventArgs e)
        {
            // trace log
            if (log.IsDebugEnabled)
                log.Debug("handling finish button clicked");

            // check title not empty
            if (title.Text == "")
            {
                resultLabel.ForeColor = Color.FromName("Red");
                resultLabel.Text = "Error: Title is required and can not be blank.";
                return;
            }

            // Assembles the contents of the file
            string fileContents = getDataDefAsString();
            if (log.IsDebugEnabled)
                log.Debug(string.Format("file contents: {0}", fileContents));

            // create and upload file
            SPSite oSiteCollection = SPContext.Current.Site;
            SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();
            Guid siteGuid = new Guid(saveLocationSiteDropDownList.SelectedValue);
            //SPWeb targetSite = collWebsite[siteGuid];
            SPWeb targetSite = ArrowUtils.getDocLibObject(siteGuid, new Guid(saveLocationLibraryDropDownList.SelectedValue)).ParentWeb;
            string outFolderGuid = saveLocationFolderDropDownList.SelectedValue;
            if (string.IsNullOrEmpty(outFolderGuid))
                ArrowUtils.CreateAndAddFileFromString(fileContents, title.Text.Trim() + ".datadef",
                    saveLocationLibraryDropDownList.SelectedValue, targetSite);
            else
                ArrowUtils.CreateAndAddFileFromString(fileContents, title.Text.Trim() + ".datadef",
                    saveLocationLibraryDropDownList.SelectedValue, targetSite, outFolderGuid);


            // Updates the status message
            resultLabel.ForeColor = Color.FromName("Blue");
            resultLabel.Text = "Data Specification File successfully created.";
            if (log.IsDebugEnabled)
                log.Debug("done handling finish button click");
        }
        /// <summary>
        /// Returns the contents of the finished datadef as a string.
        /// </summary>
        /// <returns></returns>
        private string getDataDefAsString()
        {
            // datadef vals
            string ddTitle = title.Text.Trim();
            string ddDesc = description.Text.Trim();
            DataDefinition dataDef;
            if (dataType.SelectedValue.Equals("XML"))
            {
                dataDef = new DataDefinition(ddTitle, ddDesc, "xml", labelConnStr.Text.Trim(), null, null);
                dataDef.UserName = xmlUsernameTextBox.Text.Trim();
                dataDef.Password = (string)ViewState["xmlPass"];
                //return dataDef.toXml().OuterXml;
            }
            else
            {
                dataDef = new DataDefinition(ddTitle, ddDesc,
                    providerClassFromVendorString(vendor.SelectedValue),
                    generateSqlConnStr(true),
                    vendorGuidFromVendorString(vendor.SelectedValue),
                    vendor.SelectedItem.Text.Trim());
                //return dataDef.toXml().OuterXml;
            }
            StringWriter sw = new StringWriter();
            XmlTextWriter writer = new XmlTextWriter(sw);
            dataDef.toXml().WriteTo(writer);
            return sw.ToString();
        }
        /// <summary>
        /// Gets the provider class from the specified vendor list item string.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private string providerClassFromVendorString(string value)
        {
            if (value == null)
                throw new ArgumentNullException("Vendor list item string must not be null.");
            int posSemi1 = value.IndexOf(';');
            int posSemi2 = value.IndexOf(';', posSemi1 + 1);
            if (posSemi2 == -1)
                throw new ArgumentException("Vendor list item string must be of form vendor;provider;guid.");
            int len = posSemi2 - (posSemi1 + 1);
            return value.Substring(posSemi1 + 1, len);
        }
        /// <summary>
        /// Gets the provider subtype from the specified vendor list item string.
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        private string vendorGuidFromVendorString(string value)
        {
            if (value == null)
                throw new ArgumentNullException("Vendor list item string must not be null.");
            int posSemi1 = value.IndexOf(';');
            int posSemi2 = value.IndexOf(';', posSemi1 + 1);
            if (posSemi2 == -1)
                throw new ArgumentException("Vendor list item string must be of form vendor;provider;guid.");
            int len = value.Length - (posSemi2 + 1);
            return value.Substring(posSemi2 + 1, len);
        }
        /// <summary>
        /// This function is called when ever the test button is pressed in the wizard.
        /// This attempts to connect to the specified data source and updates a status message depending on the result.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void testBtn_Click(object sender, EventArgs e)
        {
            try
            {
                // trace log
                if (log.IsDebugEnabled)
                    log.Debug("handling test button clicked");

                if (dataType.SelectedValue == "XML")
                {
                    if (log.IsDebugEnabled)
                        log.Debug(string.Format("test xml connection: {0}", labelConnStr.Text.Trim()));
                    // bugbug: do we need a permission check here?
                    Stream xml = ArrowUtils.GetSPFileStream(labelConnStr.Text.Trim());
                    XmlReader xmlReader = XmlReader.Create(xml);
                    while (xmlReader.Read())
                        // nothing - just make sure can read all
                        ;
                    xml.Close();
                }
                else
                {
                    string vendorName = vendor.SelectedItem.Text.Trim();
                    string providerClass = providerClassFromVendorString(vendor.SelectedValue);
                    WrVendor v = createVendor();
                    WrConnection c = v.CreateConnection();
                    c.ConnectionString = generateSqlConnStr(true);
                    c.Open();
                    c.Close();
                }
                testLabel.ForeColor = Color.FromName("Blue");
                testLabel.Text = "Connection OK.";
            }
            catch (Exception ex)
            {
                ArrowUtils.LogWarnException(log, ex);
                testLabel.ForeColor = Color.FromName("Red");
                testLabel.Text = "Error: " + ex.Message;
            }
        }

        /// <summary>
        /// This function is called when ever site in xmlSitesDropDownList is changed.
        /// It then appropriately updates the xmlLibs DropDownList with the libraries in the chosen xmlSitesDropDownList site
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void xmlSitesDropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            // trace log
            if (log.IsDebugEnabled)
                log.Debug("xml site dropdown changed");

            xmlLibs.Items.Clear();
            if (xmlSitesDropDownList.Items.Count != 0)
            {
                SPSite oSiteCollection = SPContext.Current.Site;

                SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();
                Guid siteGuid = new Guid(xmlSitesDropDownList.SelectedValue);
                SPWeb site = collWebsite[siteGuid];
                foreach (SPList list in site.Lists)
                {
                    if (list is SPDocumentLibrary && !list.Hidden)
                    {
                        xmlLibs.Items.Add(new ListItem(list.Title, list.ID.ToString()));
                    }
                }

            }
            xmlLibs_SelectedIndexChanged(null, null);
        }

        /// <summary>
        /// This function is called when ever document library in xmlLibs is changed.
        /// It then appropriately updates the xmlFiles DropDownList with the files in the chosen xmlLibs library
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void xmlLibs_SelectedIndexChanged(object sender, EventArgs e)
        {
            // load new xml files from selected lib
            if (log.IsDebugEnabled)
                log.Debug("loading new xml files from newly selected lib");
            xmlFiles.Items.Clear();
            if (xmlLibs.Items.Count != 0)
            {
                SPSite oSiteCollection = SPContext.Current.Site;

                SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();
                Guid siteGuid = new Guid(xmlSitesDropDownList.SelectedValue);
                SPWeb site = collWebsite[siteGuid];

                Guid libraryID = new Guid(xmlLibs.SelectedValue);
                SPDocumentLibrary library = (SPDocumentLibrary)site.Lists[libraryID];

                ArrayList sortedItems = new ArrayList();
                foreach (SPListItem item in library.Items)
                {
                    sortedItems.Add(item);
                }
                sortedItems.Sort(new ArrowUtils.SPListItemComparer());

                foreach (SPListItem item in sortedItems)
                {
                    SPFile file = item.File;
                    if (file.Name.EndsWith(".xml"))
                        xmlFiles.Items.Add(new ListItem(file.Name, item.UniqueId.ToString()));
                }
            }

            // put "none" items in if no files available
            if (xmlLibs.Items.Count == 0)
            {
                xmlLibs.Items.Add(new ListItem("<None>", ""));
                xmlFiles.Items.Add(new ListItem("<None>", ""));
            }
            else if (xmlFiles.Items.Count == 0)
            {
                xmlFiles.Items.Add(new ListItem("<None>", ""));
            }

            // put "none" item if empty site list
            if (xmlSitesDropDownList.Items.Count == 0)
            {
                if (log.IsWarnEnabled)
                    log.Warn("The site list is empty; adding 'none' item");
                // Not sure how this would be possible, but just in case.
                xmlSitesDropDownList.Items.Add(new ListItem("<None>", ""));
            }
        }

        /// <summary>
        /// This function is called when ever document library in saveLocationSiteDropDownList is changed.
        /// It then appropriately updates the xmlFiles saveLocationLibraryDropDownList with the files in the chosen saveLocationSiteDropDownList library
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void saveLocationSiteDropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            // trace log
            if (log.IsDebugEnabled)
                log.Debug("save location site item selected; updating save location library list");

            saveLocationLibraryDropDownList.Items.Clear();
            if (saveLocationSiteDropDownList.Items.Count != 0)
            {
                SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();
                
                Guid siteGuid = new Guid(saveLocationSiteDropDownList.SelectedValue);
                SPWeb site = collWebsite[siteGuid];
                foreach (SPList list in site.Lists)
                {
                    if (list is SPDocumentLibrary && !list.Hidden)
                    {
                        saveLocationLibraryDropDownList.Items.Add(new ListItem(list.Title, list.ID.ToString()));
                    }
                }

                saveLocationLibraryDropDownList_SelectedIndexChanged(null, null);
            }
            if (saveLocationLibraryDropDownList.Items.Count == 0)
            {
                saveLocationLibraryDropDownList.Items.Add(new ListItem("<None>", ""));
            }
        }
        /// <summary>
        /// This function is called when ever document library in saveLocationLibraryDropDownList is changed.
        /// It then appropriately updates the saveLocationFolderDropDownList
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void saveLocationLibraryDropDownList_SelectedIndexChanged(object sender, EventArgs e)
        {
            // trace log
            if (log.IsDebugEnabled)
                log.Debug("Save location library item selected; updating save location folders");

            saveLocationFolderDropDownList.Items.Clear();

            saveLocationFolderDropDownList.Items.Add(new ListItem("<None>", string.Empty));
            
            // add the new folder items to the save folder list, or <none> if none
            if (saveLocationLibraryDropDownList.Items.Count != 0)
            {
                SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();

                // get selected doc lib
                Guid siteGuid = new Guid(saveLocationSiteDropDownList.SelectedValue);
                SPWeb site = collWebsite[siteGuid];
                string sListGuid = saveLocationLibraryDropDownList.SelectedValue;
                if (string.IsNullOrEmpty(sListGuid))
                    return;
                Guid listGuid = new Guid(sListGuid);
                SPDocumentLibrary lib = (SPDocumentLibrary)site.Lists[listGuid];

                // add items to folder list
                foreach (SPListItem folderItem in lib.Folders)
                {
                    if (folderItem.Folder != null)
                    {
                        SPFolder folder = folderItem.Folder;
                        saveLocationFolderDropDownList.Items.Add(
                            new ListItem(folder.Name, folder.UniqueId.ToString())
                            );
                    }
                }
            }
        }

        #endregion

        #region delegate function helper functions

        /// <summary>
        /// Gets the server relative url of the specified file.
        /// </summary>
        /// <param name="siteGuid">SPWeb the file is located in.</param>
        /// <param name="docLibGuid">doc lib file is located in</param>
        /// <param name="fileGuid">guid of the file</param>
        /// <returns></returns>
        public string getRelativePath(Guid siteGuid, Guid docLibGuid, Guid fileGuid)
        {
            SPWeb site = SPContext.Current.Site.OpenWeb(siteGuid);
            SPDocumentLibrary fileLib = (SPDocumentLibrary)site.Lists[docLibGuid];
            SPFile file = ArrowUtils.GetSPFileFromDocLib(fileLib, fileGuid.ToString());
            return file.ServerRelativeUrl;
        }

        /// <summary>
        /// Gets the absolute url of the file.
        /// </summary>
        /// <param name="siteGuid">SPWeb file is located in</param>
        /// <param name="docLibGuid">Doc lib file is located in</param>
        /// <param name="fileGuid">file guid</param>
        /// <returns></returns>
        public string getAbsolutePath(Guid siteGuid, Guid docLibGuid, Guid fileGuid)
        {
            return SPContext.Current.Site.MakeFullUrl(getRelativePath(siteGuid, docLibGuid, fileGuid));
        }

        /// <summary>
        /// This function create a WrVendor object using the vendor selected in the vendor DropDownList
        /// </summary>
        private WrVendor createVendor()
        {
            string providerClass = providerClassFromVendorString(vendor.SelectedValue);
            return WrProviderFactories.CreateProvider(vendor.SelectedItem.Text.Trim(), "", providerClass);
        }

        /// <summary>
        /// This function determines the vendors applicable to the machine hosting the web part, and appropriately populates the vendor DropDownList
        /// </summary>
        private void populateVendors()
        {
            vendor.Items.Clear();
            WrProviderFactories.ProviderInfo providers = WrProviderFactories.GetAllProviders();
            WrVendor[] vendors = providers.Vendors;
            foreach (WrVendor singleVendor in vendors)
            {
                // these 3 values for WrProviderFactories.CreateProvider
                string value = string.Format("{0};{1};{2}", singleVendor.Name, singleVendor.ProviderClass, singleVendor.GUID);
                vendor.Items.Add(new ListItem(singleVendor.Name, value));
            }
            if (vendor.Items.Count == 0)
            {
                vendor.Items.Add(new ListItem("<None>", ""));
            }
        }

        /// <summary>
        /// This function determines the providers applicable to the user chosen vendor, and appropriately populates the provider DropDownList
        /// </summary>
        private void populateProviders()
        {
            WrVendor selectedVendor = createVendor();
            provider.Items.Clear();
            foreach (WrVendor.OdbcDriverInfo info in selectedVendor.GetOdbcProviders())
            {
                provider.Items.Add(new ListItem(info.Name, info.Driver));
            }
            if (provider.Items.Count == 0)
            {
                provider.Items.Add(new ListItem("<None>", ""));
            }
        }

        /// <summary>
        /// This function determines the servers applicable to vendor/provider combination, and appropriately populates the dropDownServer DropDownList
        /// </summary>
        private void populateServers()
        {
            WrVendor selectedVendor = createVendor();
            IWrServer[] servers = selectedVendor.GetServers();
            dropDownServer.Items.Clear();
            foreach (IWrServer aServer in servers)
            {
                dropDownServer.Items.Add(new ListItem(aServer.Name, aServer.Name));
            }
            if (dropDownServer.Items.Count == 0)
            {
                dropDownServer.Items.Add(new ListItem("<None>", ""));
            }
        }

        /// <summary>
        /// This function determines the vendors applicable to the machine hosting the web part, and appropriately populates the vendor DropDownList
        /// </summary>
        private void populateDatabases()
        {
            WrVendor selectedVendor = createVendor();
            // may want to set provider here
            WrCredentials cred = getCredentials();
            IWrServer selectedServer = selectedVendor.CreateServer(getServerName());
            IWrDatabase[] allDatabases = selectedServer.GetDatabases(cred);
            database.Items.Clear();
            foreach (IWrDatabase selectedDatabase in allDatabases)
            {
                database.Items.Add(new ListItem(selectedDatabase.Name, selectedDatabase.Name));
            }
            if (database.Items.Count == 0)
            {
                database.Items.Add(new ListItem("<None>", ""));
            }
        }

        /// <summary>
        /// Returns the server name chosen by the user
        /// </summary>
        private String getServerName()
        {
            if (serverSelectionType.SelectedValue == "dropDown")
                return dropDownServer.SelectedValue;
            else if (serverSelectionType.SelectedValue == "text")
                return textBoxServer.Text.Trim();
            return "";
        }

        /// <summary>
        /// Returns the credentials selected by the user, if any
        /// </summary>
        private WrCredentials getCredentials()
        {
            if (loginType.SelectedValue == "namePass")
                return new WrCredentials(username.Text.Trim(), (String)ViewState["pass"]);
            return new WrCredentials();
        }

        /// <summary>
        /// Generates and returns the connection string for an SQL data source defined in the Step-by-Step process of the wizard
        /// </summary>
        private String generateSqlConnStr(bool display)
        {
            if (connStr.Text != null && !string.IsNullOrEmpty(connStr.Text.Trim()))
                return connStr.Text;

            WrVendor selectedVendor = createVendor();
            if (selectedVendor.HasProviders)
                selectedVendor.OdbcProvider = provider.SelectedValue;

            String connStrServer = getServerName();

            string connStrDatabase = "";
            if (selectedVendor.CanEnumerateDatabases)
                connStrDatabase = database.SelectedValue;

            WrCredentials connStrCreds = getCredentials();

            return selectedVendor.ConnectionString(connStrServer, connStrDatabase, connStrCreds, display);
        }

        /// <summary>
        /// Populates the summary with the information that will be used to create the *.datadef file
        /// </summary>
        private void populateSummary(String connStr)
        {
            labelTitle.Text = title.Text.Trim();
            labelDescription.Text = description.Text.Trim();
            labelLocation.Text = saveLocationLibraryDropDownList.SelectedItem.Text.Trim();
            labelConnStr.Text = connStr;
            testLabel.Text = "";
            resultLabel.Text = "";
        }

        #endregion

        #region table creation functions

        /// <summary>
        /// Creates the basic table asking for information about the *.datadef file.
        /// sets title(TextBox), description(TextBox), saveLocationLibDropDownList(DropDownList), dataType (RadioButtonList, "SQL"/"XML")
        /// </summary>
        private Table createTable0()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 1.");

            //SPWeb site = SPContext.Current.Web;

            Table t = createEmptyTable(5, 2, 41, 125);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));

            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>This wizard helps you create a data defintion file to use for creating report definitions.</u>"));

            // 1,0
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("Title(required):"));

            // 1,1
            title = new TextBox();
            title.ID = "title";
            title.Text = "Enter title";
            title.Width = 225;
            t.Rows[1].Cells[1].Controls.Add(title);

            titleTextBoxValidator = new RequiredFieldValidator();
            titleTextBoxValidator.Display = ValidatorDisplay.Dynamic;
            titleTextBoxValidator.ErrorMessage = "* Enter a title";
            titleTextBoxValidator.Text = "* Enter a title";
            titleTextBoxValidator.ControlToValidate = "title";
            titleTextBoxValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            t.Rows[1].Cells[1].Controls.Add(titleTextBoxValidator);

            // 2,0
            t.Rows[2].Cells[0].Controls.Add(new LiteralControl("Description:"));

            // 2,1
            description = new TextBox();
            description.ID = "description";
            description.Width = 225;
            description.TextMode = TextBoxMode.MultiLine;
            t.Rows[2].Cells[1].Controls.Add(description);

            // 3,0
            t.Rows[3].Cells[0].Controls.Add(new LiteralControl("Save Location:"));
            
            // 3,1
            t.Rows[3].Cells[1].Controls.Add(new LiteralControl("Site<br/>"));
            saveLocationSiteDropDownList = new DropDownList();
            saveLocationSiteDropDownList.AutoPostBack = true;
            saveLocationSiteDropDownList.SelectedIndexChanged += new EventHandler(saveLocationSiteDropDownList_SelectedIndexChanged);
            t.Rows[3].Cells[1].Controls.Add(saveLocationSiteDropDownList);
            
            
            // get sorted collection of webs
            SPSite oSiteCollection = SPContext.Current.Site;
            SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();
            ArrayList sortedWebs = new ArrayList(collWebsite.Count);
            foreach (SPWeb oWebsite in collWebsite)
            {
                sortedWebs.Add(oWebsite);
            }
            sortedWebs.Sort(new ArrowUtils.SPWebSortComparer());

            // create menu item foreach web
            foreach (SPWeb oWebsite in sortedWebs)
            {
                saveLocationSiteDropDownList.Items.Add(new ListItem(oWebsite.Title, oWebsite.ID.ToString()));
                oWebsite.Dispose();
            }

            saveLocationSiteDropDownList.SelectedIndex = saveLocationSiteDropDownList.Items.IndexOf(saveLocationSiteDropDownList.Items.FindByValue(SPContext.Current.Web.ID.ToString()));
            
            // doc lib list
            t.Rows[3].Cells[1].Controls.Add(new LiteralControl("<br/><br/>"));
            t.Rows[3].Cells[1].Controls.Add(new LiteralControl("Document Library<br/>"));
            saveLocationLibraryDropDownList = new DropDownList();
            saveLocationLibraryDropDownList.ID = "saveLocation";
            saveLocationLibraryDropDownList.AutoPostBack = true;
            saveLocationLibraryDropDownList.SelectedIndexChanged += new EventHandler(saveLocationLibraryDropDownList_SelectedIndexChanged);
            t.Rows[3].Cells[1].Controls.Add(saveLocationLibraryDropDownList);

            // folder list
            t.Rows[3].Cells[1].Controls.Add(new LiteralControl("<br/><br/>"));
            t.Rows[3].Cells[1].Controls.Add(new LiteralControl("Folder<br/>"));
            saveLocationFolderDropDownList = new DropDownList();
            saveLocationFolderDropDownList.ID = "saveFolder";
            t.Rows[3].Cells[1].Controls.Add(saveLocationFolderDropDownList);

            // add list items
            saveLocationSiteDropDownList_SelectedIndexChanged(null, null);

            saveLocationLibraryDropDownListValidator = new RequiredFieldValidator();
            saveLocationLibraryDropDownListValidator.Display = ValidatorDisplay.Dynamic;
            saveLocationLibraryDropDownListValidator.ErrorMessage = "* Select a library";
            saveLocationLibraryDropDownListValidator.Text = "* Select a library";
            saveLocationLibraryDropDownListValidator.ControlToValidate = "saveLocation";
            saveLocationLibraryDropDownListValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            saveLocationLibraryDropDownListValidator.InitialValue = "";
            t.Rows[3].Cells[1].Controls.Add(saveLocationLibraryDropDownListValidator);

            // 4,0
            t.Rows[4].Cells[0].Controls.Add(new LiteralControl("Type of Data:"));

            // 4,1
            dataType = new RadioButtonList();
            dataType.ID = "dataType";
            ListItem sqlRadioBtn = new ListItem("SQL", "SQL");
            dataType.Items.Add(sqlRadioBtn);
            dataType.Items.Add(new ListItem("XML", "XML"));
            sqlRadioBtn.Selected = true;
            t.Rows[4].Cells[1].Controls.Add(dataType);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 1.");
            
            return t;
        }
        /// <summary>
        /// Creates the table used for SQL vendor selection and method of database selection
        /// sets vendor(DropDownList) and inputType("StepByStep"/"ConnStr")
        /// </summary>
        private Table createTable1()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 2.");

            Table t = createEmptyTable(3, 2, 41, 125);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));
            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Select the type of your SQL server and what method you'd like to use to select your database.</u>"));

            // 1,0
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("Make & Model:"));

            // 1,1
            vendor = new DropDownList();
            vendor.ID = "vendor";
            t.Rows[1].Cells[1].Controls.Add(vendor);

            vendorDropDownListValidator = new RequiredFieldValidator();
            vendorDropDownListValidator.Display = ValidatorDisplay.Dynamic;
            vendorDropDownListValidator.ErrorMessage = "* Select a valid vendor";
            vendorDropDownListValidator.Text = "* Select a valid vendor";
            vendorDropDownListValidator.ControlToValidate = "vendor";
            vendorDropDownListValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            vendorDropDownListValidator.InitialValue = "";
            t.Rows[1].Cells[1].Controls.Add(vendorDropDownListValidator);

            // 2,0
            t.Rows[2].Cells[0].Controls.Add(new LiteralControl("Select the database:"));

            // 2,1
            inputType = new RadioButtonList();
            inputType.ID = "inputType";
            ListItem sqlRadioBtn = new ListItem("Step by Step", "StepByStep");
            inputType.Items.Add(sqlRadioBtn);
            inputType.Items.Add(new ListItem("Expert(connection string)", "ConnStr"));
            sqlRadioBtn.Selected = true;
            t.Rows[2].Cells[1].Controls.Add(inputType);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 2.");

            return t;
        }
        /// <summary>
        /// Creates the table used to select the provider
        /// Sets provider(DropDownList)
        /// </summary>
        private Table createTable2()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 3.");

            Table t = createEmptyTable(2, 2, 41, 125);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));
            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Select your data source provider.</u>"));

            // 1,0
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("Provider:"));
            // 1,1
            provider = new DropDownList();
            provider.ID = "provider";
            t.Rows[1].Cells[1].Controls.Add(provider);

            providerDropDownListValidator = new RequiredFieldValidator();
            providerDropDownListValidator.Display = ValidatorDisplay.Dynamic;
            providerDropDownListValidator.ErrorMessage = "* Select a valid provider";
            providerDropDownListValidator.Text = "* Select a valid provider";
            providerDropDownListValidator.ControlToValidate = "provider";
            providerDropDownListValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            providerDropDownListValidator.InitialValue = "";
            t.Rows[1].Cells[1].Controls.Add(providerDropDownListValidator);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 3.");

            return t;
        }
        /// <summary>
        /// Creates the table used to select the server and provide server-access credentials
        /// sets serverSelectionType(RadioButtonList, "dropDown"/"text"), dropDownServer(DropDownList), textBoxServer(TextBox), loginType(RadioButtonList, "this"/"namePass"), username(TextBox), password(TextBox)
        /// </summary>
        private Table createTable3()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 4.");

            Table t = createEmptyTable(7, 2, 41, 125);

            // title, step description
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Select your server and, if necessary, enter login information.</u>"));

            // server selection
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("<b>Select the Server</b>"));
            serverSelectionType = new RadioButtonList();
            serverSelectionType.ID = "serverSelectionType";
            ListItem dropDownRadioBtn = new ListItem("Select the server:<br/> or", "dropDown");
            serverSelectionType.Items.Add(dropDownRadioBtn);
            serverSelectionType.Items.Add(new ListItem("Enter server name:", "text"));
            dropDownRadioBtn.Selected = true;
            t.Rows[2].Cells[0].Controls.Add(serverSelectionType);
            // 2,1
            dropDownServer = new DropDownList();
            dropDownServer.ID = "dropDownServer";
            //dropDownServer.Width = 100;// 225;
            t.Rows[2].Cells[1].Controls.Add(dropDownServer);
            t.Rows[2].Cells[1].Controls.Add(new LiteralControl("<br/><br/>"));
            textBoxServer = new TextBox();
            textBoxServer.ID = "textBoxServer";
            textBoxServer.Width = 225;
            t.Rows[2].Cells[1].Controls.Add(textBoxServer);
            //3,0
            t.Rows[3].Cells[0].Controls.Add(new LiteralControl("<b>Enter Login</b>"));
            //3,1
            //4,0
            loginType = new RadioButtonList();
            loginType.ID = "loginType";
            //ListItem sqlRadioBtn = new ListItem("Use this login", "this");
            ListItem sqlRadioBtn = new ListItem("Use Windows Identity if applicable", "this");
            loginType.Items.Add(sqlRadioBtn);
            loginType.Items.Add(new ListItem("Provide name and password", "namePass"));
            sqlRadioBtn.Selected = true;
            t.Rows[4].Cells[0].Controls.Add(loginType);
            //4,1
            //5,0
            t.Rows[5].Cells[0].Controls.Add(new LiteralControl("Username:"));
            //5,1
            username = new TextBox();
            username.ID = "username";
            username.Width = 225;
            t.Rows[5].Cells[1].Controls.Add(username);
            //6,0
            t.Rows[6].Cells[0].Controls.Add(new LiteralControl("Password:"));
            //6,1
            password = new TextBox();
            password.ID = "password";
            password.Width = 225;
            password.TextMode = TextBoxMode.Password;
            t.Rows[6].Cells[1].Controls.Add(password);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 4.");

            return t;
        }
        /// <summary>
        /// Creates the table used to select the database from the available databases on the server
        /// sets database(DropDownList)
        /// </summary>
        private Table createTable4()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 5.");

            Table t = createEmptyTable(2, 2, 41, 125);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));
            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Select your database.</u>"));

            // 1,0
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("Database:"));
            // 1,1
            database = new DropDownList();
            database.ID = "database";
            t.Rows[1].Cells[1].Controls.Add(database);

            databaseDropDownListValidator = new RequiredFieldValidator();
            databaseDropDownListValidator.Display = ValidatorDisplay.Dynamic;
            databaseDropDownListValidator.ErrorMessage = "* Select a valid database";
            databaseDropDownListValidator.Text = "* Select a valid database";
            databaseDropDownListValidator.ControlToValidate = "database";
            databaseDropDownListValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            databaseDropDownListValidator.InitialValue = "";
            t.Rows[1].Cells[1].Controls.Add(databaseDropDownListValidator);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 5.");

            return t;
        }
        /// <summary>
        /// Creates the table used to directly input a connection string
        /// sets database(DropDownList)
        /// </summary>
        private Table createTable5()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 6.");

            Table t = createEmptyTable(2, 2, 1, 1);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));
            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Enter your connection string.</u>"));

            // 1,0
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("Connection String:"));
            // 1,1
            connStr = new TextBox();
            connStr.ID = "connStr";
            connStr.Width = 225;
            connStr.TextMode = TextBoxMode.MultiLine;
            t.Rows[1].Cells[1].Controls.Add(connStr);

            connStrTextBoxValidator = new RequiredFieldValidator();
            connStrTextBoxValidator.Display = ValidatorDisplay.Dynamic;
            connStrTextBoxValidator.ErrorMessage = "* Select a valid connection string";
            connStrTextBoxValidator.Text = "* Select a valid connection string";
            connStrTextBoxValidator.ControlToValidate = "connStr";
            connStrTextBoxValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            t.Rows[1].Cells[1].Controls.Add(connStrTextBoxValidator);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 6.");

            return t;
        }
        /// <summary>
        /// Creates the table used to select the XML file to use as a data source
        /// sets xmlLib(DropDownList) amd xmlFilename(DropDownList)
        /// </summary>
        private Table createTable6()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 7.");

            //SPWeb site = SPContext.Current.Web;

            Table t = createEmptyTable(5, 2, 41, 125);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));

            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Select your XML data file.  In needed, input user infomation to access the file.</u>"));

            // error message label
            lblXmlFileStepErrorMessage = new Label();
            lblXmlFileStepErrorMessage.Style["color"] = "red";
            t.Rows[1].Cells[1].Controls.Add(lblXmlFileStepErrorMessage);

            // 1,0
            t.Rows[2].Cells[0].Controls.Add(new LiteralControl("XML Date File"));

            // 1,1
            t.Rows[2].Cells[1].Controls.Add(new LiteralControl("Site<br/>"));

            //if (HttpContext.Current.Cache["ReportName_Global"] != null)
            //    t.Rows[1].Cells[1].Controls.Add(new LiteralControl((string)HttpContext.Current.Cache["ReportName_Global"]));

            // Entry 1
            xmlSitesDropDownList = new DropDownList();
            xmlSitesDropDownList.AutoPostBack = true;
            xmlSitesDropDownList.SelectedIndexChanged += new EventHandler(xmlSitesDropDownList_SelectedIndexChanged);
            SPSite oSiteCollection = SPContext.Current.Site;

            // get sorted collection of webs
            SPWebCollection collWebsite = ArrowUtils.GetSPWebCollectionFromCurrentSite();
            ArrayList sortedWebs = new ArrayList(collWebsite.Count);
            foreach (SPWeb oWebsite in collWebsite)
            {
                sortedWebs.Add(oWebsite);
            }
            sortedWebs.Sort(new ArrowUtils.SPWebSortComparer());

            // add each web menu item
            foreach (SPWeb oWebsite in sortedWebs)
            {
                xmlSitesDropDownList.Items.Add(new ListItem(oWebsite.Title, oWebsite.ID.ToString()));
                oWebsite.Dispose();
            }

            xmlSitesDropDownList.SelectedIndex = xmlSitesDropDownList.Items.IndexOf(xmlSitesDropDownList.Items.FindByValue(SPContext.Current.Web.ID.ToString()));
            t.Rows[2].Cells[1].Controls.Add(xmlSitesDropDownList);

            // Entry 2
            t.Rows[2].Cells[1].Controls.Add(new LiteralControl("<br/><br/>"));
            t.Rows[2].Cells[1].Controls.Add(new LiteralControl("Document Library<br/>"));
            xmlLibs = new DropDownList();
            xmlLibs.ID = "xmlLib";
            xmlLibs.SelectedIndexChanged += new EventHandler(xmlLibs_SelectedIndexChanged);
            xmlLibs.AutoPostBack = true;
            t.Rows[2].Cells[1].Controls.Add(xmlLibs);

            // Entry 3
            t.Rows[2].Cells[1].Controls.Add(new LiteralControl("<br/><br/>"));
            t.Rows[2].Cells[1].Controls.Add(new LiteralControl("File Name<br/>"));
            xmlFiles = new DropDownList();
            xmlFiles.ID = "xmlFilename";
            t.Rows[2].Cells[1].Controls.Add(xmlFiles);
            xmlSitesDropDownList_SelectedIndexChanged(null, null);

            xmlFilesDropDownListValidator = new RequiredFieldValidator();
            xmlFilesDropDownListValidator.Display = ValidatorDisplay.Dynamic;
            xmlFilesDropDownListValidator.ErrorMessage = "* Select a valid xml file";
            xmlFilesDropDownListValidator.Text = "* Select a valid file";
            xmlFilesDropDownListValidator.ControlToValidate = "xmlFilename";
            xmlFilesDropDownListValidator.ValidationGroup = "validationGroup" + this.UniqueID;
            xmlFilesDropDownListValidator.InitialValue = "";
            t.Rows[2].Cells[1].Controls.Add(xmlFilesDropDownListValidator);

            // 2,0
            //"Enter credentials to access XML file, if needed."
            t.Rows[3].Cells[0].Controls.Add(new LiteralControl("Username:"));

            // 2,1
            xmlUsernameTextBox = new TextBox();
            xmlUsernameTextBox.Width = 225;
            t.Rows[3].Cells[1].Controls.Add(xmlUsernameTextBox);

            // 3,0
            t.Rows[4].Cells[0].Controls.Add(new LiteralControl("Password: "));

            // 3,1
            xmlPasswordTextBox = new TextBox();
            xmlPasswordTextBox.Width = 225;
            xmlPasswordTextBox.TextMode = TextBoxMode.Password;
            t.Rows[4].Cells[1].Controls.Add(xmlPasswordTextBox);

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 7.");

            return t;
        }
        /// <summary>
        /// Creates the table used to display the summary and provide testing of the selected data source
        /// nothing is set
        /// </summary>
        private Table createTable7()
        {
            if (log.IsDebugEnabled)
                log.Debug("Creating step 8.");

            Table t = createEmptyTable(7, 2, 1, 1);

            // 0,0
            t.Rows[0].Cells[0].Controls.Add(new LiteralControl("<b>Arrow Data Definition Wizard</b>"));
            // 0,1
            t.Rows[0].Cells[1].Controls.Add(new LiteralControl("<u>Summary. Click the Finish button to generate a data definition file.</u>"));

            // 1,0
            t.Rows[1].Cells[0].Controls.Add(new LiteralControl("Title:"));
            // 1,1
            labelTitle = new Label();
            t.Rows[1].Cells[1].Controls.Add(labelTitle);
            // 2,0
            t.Rows[2].Cells[0].Controls.Add(new LiteralControl("Description:"));
            // 2,1
            labelDescription = new Label();
            t.Rows[2].Cells[1].Controls.Add(labelDescription);
            // 3,0
            t.Rows[3].Cells[0].Controls.Add(new LiteralControl("Location:"));
            // 3,1
            labelLocation = new Label();
            t.Rows[3].Cells[1].Controls.Add(labelLocation);
            // 4,0
            t.Rows[4].Cells[0].Controls.Add(new LiteralControl("Data Connection:"));
            // 4,1
            labelConnStr = new Label();
            t.Rows[4].Cells[1].Controls.Add(labelConnStr);
            // 5,0
            testBtn = new Button();
            testBtn.Text = "Test Connection";
            testBtn.Click += new EventHandler(testBtn_Click);
            t.Rows[5].Cells[0].Controls.Add(testBtn);
            // 5,1
            testLabel = new Label();
            t.Rows[5].Cells[1].Controls.Add(testLabel);
            // 6,0
            resultLabel = new Label();
            t.Rows[6].Cells[0].Controls.Add(resultLabel);
            // 6,1

            if (log.IsDebugEnabled)
                log.Debug("Finished creating step 8.");

            return t;
        }

        #endregion

        #region table creation helper functions

        /// <summary>
        /// Calls the correct specific table creation function
        /// </summary>
        /// <param name="tableNum">The number of the table to be generated, so the correect controls are created</param>
        private Table createTable(int tableNum)
        {
            Table t;
            switch (tableNum)
            {
                case 0:
                    t = createTable0();
                    break;
                case 1:
                    t = createTable1();
                    break;
                case 2:
                    t = createTable2();
                    break;
                case 3:
                    t = createTable3();
                    break;
                case 4:
                    t = createTable4();
                    break;
                case 5:
                    t = createTable5();
                    break;
                case 6:
                    t = createTable6();
                    break;
                case 7:
                    t = createTable7();
                    break;
                default:
                    // Error; bad times if it ever getes here, bad times
                    return null;
            }

            t.ID = "table" + tableNum;
            t.CellPadding = 10;
            //t.BorderStyle = BorderStyle.Solid;
            //t.BorderColor = Color.FromName("Black");
            //t.BorderWidth = 1;

            return t;
        }

        /// <summary>
        /// Creates an empty table with the specified dimensions
        /// </summary>
        /// <param name="numRows">The number of rows to be created</param>
        /// <param name="numCols">The number of columns to be created</param>
        /// <param name="rowHeight">The pixel height of each row</param>
        /// <param name="rowWidth">The pixel width of each </param>
        private Table createEmptyTable(int numRows, int numCols, int rowHeight, int rowWidth)
        {
            Table t = new Table();
            for (int i = 0; i < numRows; i++)
            {
                TableRow r = new TableRow();

                for (int j = 0; j < numCols; j++)
                {
                    TableCell c = new TableCell();
                    //c.Controls.Add(new LiteralControl("row " + i.ToString() + ", cell " + j.ToString()));
                    c.Height = rowHeight;
                    c.VerticalAlign = VerticalAlign.Top;
                    /*if ((i == 0) && (j == 0))
                    {
                        c.Controls.Add(createFrameLiteralControl());
                        c.Controls.Add(changeFrameSrcLiteralControl("http://testserver2008"));
                    }*/
                    r.Cells.Add(c);
                }
                r.Width = rowWidth;
                t.Rows.Add(r);
            }
            return t;
        }

        #endregion
    }
}
